/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.swirrel.installer;

import org.swirrel.util.SwirrelException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.lang.reflect.Method;
import org.swirrel.util.Tuple;

/**
 *
 * @author Gronau
 */
public abstract class AbstractListenerInstaller implements SwirrelListenerInstaller {

    private final List<Class<? extends Annotation>> matchingAnnotations;
    private final List<Class<?>> validTypes;

    protected AbstractListenerInstaller(
            List<Class<? extends Annotation>> matchingAnnotations,
            List<Class<?>> validTypes) {
        this.matchingAnnotations = matchingAnnotations;
        this.validTypes = validTypes;
    }

    public boolean hasMatchingAnnotation(Field field) {
        for (Class<? extends Annotation> annotationClass : matchingAnnotations) {
            if (field.isAnnotationPresent(annotationClass)) {
                for (Class<?> clazz : validTypes) {
                    if (clazz.isAssignableFrom(field.getType())) {
                        return true;
                    }
                }
                return false;
            }
        }
        return false;
    }

    public void validateType(Class<?> fieldType) {
        for (Class<?> clazz : validTypes) {
            if (clazz.isAssignableFrom(fieldType)) {
                return;
            }
        }
        throw new SwirrelException("Invalid field type");
    }

    public List<Tuple<String, Boolean>> getMethodNames(Field field) {
        List<Tuple<String, Boolean>> result = new ArrayList<Tuple<String, Boolean>>();
        for (Class<? extends Annotation> annotationClass : matchingAnnotations) {
            if (field.isAnnotationPresent(annotationClass)) {
                try {
                    Method threaded = null;
                    for(Method m : annotationClass.getMethods()) {
                      if (m.getName().equals("threaded")) {
                        threaded = m; break;
                      }
                    }
                    result.add(Tuple.of(annotationClass.getMethod("value").invoke(
                            field.getAnnotation(annotationClass)).toString(),
                        threaded == null ? false :
                           (Boolean) threaded.invoke(field.getAnnotation(annotationClass))));
                } catch (RuntimeException ex) {
                    throw ex;
                } catch (Exception ex) {
                    throw new SwirrelException(ex);
                }
            } else {
                result.add(Tuple.of((String)null, (Boolean)null));
            }
        }
        return result;
    }
}
